//--------------------------------------------------------------------------------
// This file is a portion of the D2D1Renderer.  It is distributed
// under the MIT License, available in the root of this distribution and 
// at the following URL:
//
// http://www.opensource.org/licenses/mit-license.php
//
// Copyright (c) Mirco Timmermann
//
//--------------------------------------------------------------------------------
#include "TextField.h"

namespace D2 {

TextField::TextField(int x, int y, int width, int height) : DisplayObject(x, y, width, height) {
	selectable = true;

	_pointerCounter = 0;

	_textIndexIStart = 0; //current char index from the text where the pointer will be shown.
    _textIndexIEnd = 0;

	_maxInputStop = true;

	_text = "";

	_focus = false;
	_writeable = true;

	//
	//_keyString.
	//

	_fg.r = 0.8f;
	_fg.g = 0.8f;
	_fg.b = 0.8f;

	_bg.r = 0.2f;
	_bg.g = 0.2f;
	_bg.b = 0.2f;
	//_bg._a = 0.0f;

	_charWidth = 0;
	_charHeight = 0;

	_totalWidth = 0;
	_totalHeight = 0;

	showBackground = true;

#ifdef _DEBUG
	name = "D2::TextField";
#endif
}

TextField::~TextField(void) {

}

/////////////////////////////DATA////////////////////////////
bool TextField::Draw(Direct2DContext* ctx, D2D1::Matrix3x2F* mtx) {
	//ctx->_disableCamera = true;

//meassure text
	Direct2DContext::Dimension dim = ctx->measureText(_text);

	//meassure text.
	if(_text.length() == 0) {
		_charWidth = 0;
	} else {
		_charWidth = dim.width/_text.length()*1.0f; //caluclate char width;
	}

	_charHeight = dim.height; //caluclate char height;
	
	bool totalWidthChanged = false;
	bool totalHeightChanged = false;
	if(dim.width != _totalWidth) {
		totalWidthChanged = true;
	}
	if(dim.height != _totalHeight) {
		totalHeightChanged = true;
	}

	_totalWidth = dim.width;
	_totalHeight = dim.height;
//
	ctx->lineWidth = 1;

	if(showBackground) {
		ctx->SetFillStyle(_bg.r, _bg.g, _bg.b);
		ctx->fillRect(0, 0, (float)this->_width, (float)this->_height);
	}

//draw text marking.
	if(_focus) {
		DrawTextArea(ctx);
	}

//draw the text
	ctx->SetFillStyle(1.0f, 1.0f, 1.0f);
	ctx->SetStrokeStyle(_fg.r, _fg.g, _fg.b);
	ctx->fillText(_text, 0, 0, 20);

//draw text pointer.
	if(_focus) {
		DrawTextPointer(ctx);
	}

//
	if(totalWidthChanged) {
		//throw event.
		this->dispatchEvent(Event("TOTAL_WIDTH_CHANGED", this));
	}

	if(totalHeightChanged) {
		//throw event.
		this->dispatchEvent(Event("TOTAL_HEIGHT_CHANGED", this));
	}

	return true;
}

void TextField::DrawTextPointer(Direct2DContext* ctx) {
	int positionX = _charWidth * _textIndexIEnd;

	ctx->lineWidth = 1;
    ctx->SetStrokeStyle(1.0f, 1.0f, 1.0f);

    ctx->beginPath();

	ctx->moveTo(positionX, 0);
    ctx->lineTo(positionX, _totalHeight);

    ctx->stroke();
}

void TextField::OnFocusLost(const MouseEvent &e) {
	//if(_focus) { // && this.removeInputOnLostFocus) {
		//_text = _pre_text;
	//}
        
	_focus = false;
}

void TextField::OnKeyDown(const KeyboardEvent &e) {
	if(!_writeable) return;
	if(!selectable) return;

	std::string tempText = _text;

	KeyString::KeyState keyState;
	keyState.vkey = e._keyCode;
	keyState.ckey = e._charCode;
	keyState.ctrlPressed = e._strgKey;
	keyState.shiftPressed = e._shiftKey;

	int value = _keyString.Update(_text, _textIndexIEnd, _textIndexIStart, keyState);
	if(value == KeyString::RETURN) {
		_focus = false;

		Event evt("COMPLETE", this); //Event.CHANGE
        dispatchEvent(evt);
	} else if(value == KeyString::DELETE_ || value == KeyString::DELETE_) {
		Event evt("CHANGE", this); //Event.CHANGE
		dispatchEvent(evt);
	}

	//prevent for override the textField with inputs.
    if(_maxInputStop) {
		int diff = _width - (_charWidth*_text.length());
        if(diff < 0) {
			_text = tempText;
			_textIndexIEnd--;
			_textIndexIStart--;
        }
	}
}

void TextField::DrawTextArea(Direct2DContext* ctx) {
	//ctx->_disableCamera = true;
	
	ctx->SetFillStyle(0.5f, 0.5f, 0.5f);
	ctx->fillRect(_textIndexIStart*_charWidth, 0, (_textIndexIEnd - _textIndexIStart)*_charWidth, _height);

	//ctx->_disableCamera = false;
}

void TextField::OnMouseDrag0(const MouseEvent &e) {
	if(!selectable) return;

	D2D1_POINT_2F point = this->globalToLocal(e._stageX, e._stageY);

	_textIndexIEnd = GetCharIndex(point.x);
}

void TextField::OnMouseDown0(const MouseEvent &e) {
	if(!selectable) return;

	D2D1_POINT_2F point = this->globalToLocal(e._stageX, e._stageY);
        
	_textIndexIStart = GetCharIndex(point.x);
    _textIndexIEnd = _textIndexIStart;

	_focus = true;
}

/* (picking)
* returns the index where is the position on the text.
*/
int TextField::GetCharIndex(float x) {
	//calculate the index where is picking.
    //float localSpaceX = x - 0; //_text.x;

	int index = floor(x/_charWidth); //+1;

	//clamp the index.
	if(index > _text.length()) index = _text.length();
	if(index < 0) index = 0;

	return index;
}

/*
* returns the whole text.
*/
std::string TextField::GetText() {
	return _text;
}

/*
* appends a text to the exist text.
*/
void TextField::SetText(std::string text) {
	_text = text;
	setTextPointerToEnd();
}

/*
* appends a text to the exist text.
*/
void TextField::AppendText(std::string text) {
	_text += text;
	setTextPointerToEnd();
}

/*
* moves the text pointer to a different position.
*/
void TextField::setTextPointer(int index) {
	if(index < 0 || index > _text.size()) return;

	_textIndexIStart = index; //current char index from the text where the pointer will be shown.
    _textIndexIEnd = index;
}

/*
* moves the text pointer to the end of the text.
*/
void TextField::setTextPointerToEnd() {
	setTextPointer(_text.size());
}

void TextField::SetFgColor(float r, float g, float b) {
	_fg.r = r;
	_fg.g = g;
	_fg.b = b;
}

void TextField::SetBgColor(float r, float g, float b) {
	_bg.r = r;
	_bg.g = g;
	_bg.b = b;
}

float TextField::GetTotalWidth() {
	return _totalWidth;
}

float TextField::GetTotalHeight() {
	return _totalHeight;
}

}